
#include "rtt.h"

#define RTT_RTOCALC(ptr)    ((ptr)->rtt_srtt + (4.0 * (ptr)->rtt_rttvar))

int rtt_d_flag = 0;

static float rtt_minmax(float rto) {

    if (rto < RTT_RXMIN) {

        rto = RTT_RXMIN;
    }
    else if (rto > RTT_RXMAX) {

        rto = RTT_RXMAX;
    }
    return (rto);
}

void rtt_init(struct rtt_info * ptr) {

    // 初始化
    struct timeval tv;
    bzero(&tv, sizeof(struct timeval));

    gettimeofday(&tv, NULL);
    ptr->rtt_base = tv.tv_sec;
    ptr->rtt_rtt  = 0;
    ptr->rtt_srtt = 0;
    ptr->rtt_rttvar = 0.75;
    ptr->rtt_rto    = rtt_minmax(RTT_RTOCALC(ptr));
    // first RTO at (rtt + (4 * rttval) = 3 second)
}

uint32_t rtt_ts(struct rtt_info * ptr) {

    uint32_t ts;
    struct timeval tv;

    gettimeofday(&tv, NULL);
    ts = (tv.tv_sec - ptr->rtt_base) * 1000 + (tv.tv_usec / 1000);

    return (ts);
}

int rtt_start(struct rtt_info * ptr) {

    return ((int)(ptr->rtt_rto + 0.5));  /*round float to int*/
    // return value can be used as : alarm(rtt_start(&foo))
    // I think could use ceil function, for example : return (int)ceil(ptr->rtt_rto);  
}

// 更新RTT估算因子并重新计算RTO
void rtt_stop(struct rtt_info * ptr, uint32_t ms) {

    double delta;
    ptr->rtt_rtt = ms / 1000.0;
    // 
    delta = ptr->rtt_rtt - ptr->rtt_srtt;
    // update srtt
    ptr->rtt_srtt += delta/8;   // 1/8 是 施加在RTT估算因子上的增益
    if (delta < 0.0) {

        delta = -delta;
    }
    ptr->rtt_rttvar += (delta - ptr->rtt_rttvar) / 4;   // 1/4是平均偏差估算因子上的增益

    ptr->rtt_rto = rtt_minmax(RTT_RTOCALC(ptr));
}

int rtt_timeout(struct rtt_info * ptr) {

    ptr->rtt_rto *= 2;
    if (++ptr->rtt_nrexm > RTT_MAXNREXMT) {

        return(-1);
    }
    return(0);
}

void rtt_newpack(struct rtt_info * ptr) {

    ptr->rtt_nrexm = 0;
}


